#include "UIScrollPanel.h"
#include "UIButton.h"
#include "../../Input/Mouse.h"
#include <thread>

static bool		__uiscrlpnl_mouse_down_on_bar_	= false;
static bool		__uiscrlpnl_mouse_scrolling_	= false;
static float	__uiscrlpnl_previous_mouse_y_pos_;

UIScrollPanel::UIScrollPanel()
{
	Width = 184;
	Height = 240;

	SlotWidth = Width - 10;
	SlotHeight = Height / 14;

	SetupScrollbar();
}

UIScrollPanel::UIScrollPanel(float xPos, float yPos)
{
	Position = Point{ xPos, yPos };

	Width = 184;
	Height = 240;

	SlotWidth = Width - 10;
	SlotHeight = Height / 14;

	SetupScrollbar();
}

UIScrollPanel::UIScrollPanel(float xPos, float yPos, float width, float height)
{
	Position = Point { xPos, yPos };
	this->Width = width;
	this->Height = height;

	Width = 184;
	Height = 240;

	SlotWidth = Width - 10;
	SlotHeight = Height / 14;

	SetupScrollbar();
}

UIScrollPanel::~UIScrollPanel()
{
	for (std::vector<UISlot*>::iterator it = slots.begin(); it != slots.end(); it++)
	{
		if (static_cast<UISlot*>(*it)->uiElement != nullptr)
			delete static_cast<UISlot*>(*it)->uiElement;
		delete *it;
	}
}

void UIScrollPanel::SetupScrollbar()
{
	Scrollbar = std::unique_ptr<UIButton>(new UIButton(Position.x + Width - ScrollbarWidth, Position.y, ScrollbarWidth, Height / 4, "", "Arial", 1, Color::Gray, false));
	Scrollbar->Stroke = 0;
	Scrollbar->BorderStroke = 0;
	Scrollbar->AddLeftMouseClickEvent([this](UIElement* sender) {
		std::thread temp_thread([this]() {
			__uiscrlpnl_previous_mouse_y_pos_ = Mouse::GetMousePosY(this->SourceWindow);
			while (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
			{
				Sleep(10);
				float current_mouse_y_pos = Mouse::GetMousePosY(this->SourceWindow);
				float distance_moved = current_mouse_y_pos - __uiscrlpnl_previous_mouse_y_pos_;
				Scrollbar->Position.y += distance_moved;

				// Keep scrollbar in slot area's bounds
				if (Scrollbar->Position.y < this->Position.y)
					this->Scrollbar->Position.y = this->Position.y;
				else if (Scrollbar->Position.y + Scrollbar->Height > this->Position.y + this->Height)
					this->Scrollbar->Position.y = (this->Position.y + this->Height) - Scrollbar->Height;

				__uiscrlpnl_previous_mouse_y_pos_ = Mouse::GetMousePosY(this->SourceWindow);
			}
		});
		temp_thread.detach();
	});

	AddScrollWheelEvent([this](UIElement* sender, int whl_delta) {
		if (IsFocused())
		{
			if (whl_delta > 0)
				Scrollbar->Position.y -= Scrollbar->Height / ScrollDistance;
			else
				Scrollbar->Position.y += Scrollbar->Height / ScrollDistance;

			// Keep scrollbar in slot area's bounds
			if (Scrollbar->Position.y < this->Position.y)
				this->Scrollbar->Position.y = this->Position.y;
			else if (Scrollbar->Position.y + Scrollbar->Height > this->Position.y + this->Height)
				this->Scrollbar->Position.y = (this->Position.y + this->Height) - Scrollbar->Height;
		}
	});
}

UIElement* UIScrollPanel::_get_scrollbar_handle_()
{
	return Scrollbar.get();
}

void __stdcall UIScrollPanel::Draw(Graphics* graphics)
{
	if (Scrollbar->Position.y < Position.y) Scrollbar->Position.y = Position.y;
	else if (Scrollbar->Position.y > Position.y + Height - Scrollbar->Height) Scrollbar->Position.y = Position.y + Height - Scrollbar->Height;

	graphics->DrawRectangle(Position.x, Position.y, Width, Height, color.r, color.g, color.b, color.a, 0, Filled);

	if (DrawBorder)
		graphics->DrawRectangle(Position.x - BorderSize, Position.y - BorderSize, Width + (BorderSize * 2.0f), Height + (BorderSize * 2.0f), BorderColor.r, BorderColor.g, BorderColor.b, BorderColor.a, BorderStroke, false);

	float topSpaceFromScrollBar = Scrollbar->Position.y - Position.y;
	float scrolledPercent = topSpaceFromScrollBar / (this->Height - Scrollbar->Height);
	int numberOfElementsVisible = (int)((this->Height - MarginsTop + DistanceBetweenSlots) / (SlotHeight + DistanceBetweenSlots));
	if (numberOfElementsVisible > (int)slots.size())
	{
		numberOfElementsVisible = (int)slots.size();
	}
	int startIndex = (int)(scrolledPercent * (slots.size() - numberOfElementsVisible));

	// These 3 lines of code had to be put here due to a weird bug with event handling for the last visible element
	for (UISlot* slot : slots)
		if (slot->uiElement != nullptr)
			slot->uiElement->Position = Point{ -9999, -9999 };

	for (int i = startIndex; i < startIndex + numberOfElementsVisible; i++)
	{
		if ((int)slots.size() > numberOfElementsVisible)
			_Should_Draw_Scrollbar = true;
		else
			_Should_Draw_Scrollbar = false;

		float slotPosX = Position.x + MarginsLeft;
		float slotPosY = Position.y + MarginsTop + ((i - startIndex) * SlotHeight) + ((i - startIndex) * DistanceBetweenSlots);

		if (slots.at(i)->uiElement != nullptr)
		{
			slots.at(i)->uiElement->Position = Point{ slotPosX, slotPosY };
			slots.at(i)->uiElement->Width = SlotWidth;
			slots.at(i)->uiElement->Draw(graphics);
		}
	}

	Scrollbar->SourceWindow = SourceWindow;

	if (_Should_Draw_Scrollbar)
	{
		Scrollbar->Width = ScrollbarWidth;
		Scrollbar->Position.x = Position.x + Width - ScrollbarWidth;
		Scrollbar->Draw(graphics);
	}
}

void __stdcall UIScrollPanel::FadeIn(int time)
{
	for (UISlot* slot : slots)
	{
		std::thread fadein_thread([slot, &time]() {
			slot->uiElement->FadeIn(time);
		});
		fadein_thread.detach();
	}

	UIElement::FadeIn(time);
	Scrollbar->Visible = true;
}

void __stdcall UIScrollPanel::FadeOut(int time)
{
	Scrollbar->Visible = false;

	for (UISlot* slot : slots)
	{
		std::thread fadeout_thread([slot, &time]() {
			slot->uiElement->FadeOut(time);
		});
		fadeout_thread.detach();
	}

	UIElement::FadeOut(time);
}

void UIScrollPanel::AddElement(UIElement* elem)
{
	UISlot* slot = new UISlot();
	slot->width = SlotWidth;
	slot->height = SlotHeight;

	elem->Width = slot->width;
	elem->Height = slot->height;
	slot->uiElement = elem;

	this->slots.push_back(slot);
}

void UIScrollPanel::AddEmptySlot()
{
	UISlot* slot = new UISlot();
	slot->width = SlotWidth;
	slot->height = SlotHeight;
	// No UIElement will be added to this slot therefore creating an empty space
	this->slots.push_back(slot);
}

void UIScrollPanel::RemoveElement(int index)
{
	if (index < (int)slots.size() && index >= 0 && slots.size() > 0)
		slots.erase(slots.begin() + index);
}

void UIScrollPanel::RemoveElement(UIElement* elem)
{
	for (int i = 0; i < (int)slots.size(); i++)
	{
		if (slots.at(i)->uiElement == elem)
		{
			slots.erase(slots.begin() + i);
			break;
		}
	}
}

void UIScrollPanel::RemoveAllElements()
{
	for (std::vector<UISlot*>::iterator it = slots.begin(); it != slots.end(); it++)
	{
		if (static_cast<UISlot*>(*it)->uiElement != nullptr)
			delete static_cast<UISlot*>(*it)->uiElement;
		delete *it;
		slots.clear();
	}
}

int UIScrollPanel::IndexOf(UIElement* elem)
{
	for (int i = 0; i < (int)slots.size(); i++)
		if (slots.at(i)->uiElement == elem)
			return i;
	return -1;
}
